-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
USB Host UVC driver version 2 #84
base: master
Are you sure you want to change the base?
Conversation
7adb8ec
to
e9a9097
Compare
host/class/uvc/usb_host_uvc_2/host_test/main/parsing/descriptors/old.hpp
Outdated
Show resolved
Hide resolved
host/class/uvc/usb_host_uvc_2/host_test/main/parsing/test_parsing_customer_dual.cpp
Outdated
Show resolved
Hide resolved
host/class/uvc/usb_host_uvc_2/host_test/main/parsing/test_parsing_elp_h264.cpp
Outdated
Show resolved
Hide resolved
host/class/uvc/usb_host_uvc_2/host_test/main/parsing/test_parsing_logitech_c270.cpp
Outdated
Show resolved
Hide resolved
e9a9097
to
4157f1b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@peter-marcisovsky Thank you very much for such a thorough review!
I fixed most of the things, answered other and left a few for later.
I left the changes in separate comment for now, so it is easier to review
host/class/uvc/usb_host_uvc_2/host_test/main/parsing/descriptors/old.hpp
Outdated
Show resolved
Hide resolved
host/class/uvc/usb_host_uvc_2/examples/basic_uvc_stream/main/basic_uvc_stream.c
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey Tomas,
I did the first round and it works! Cool!
Regarding the changes, I did check the:
- READMEs and Description
- Folder struct and APIs
Couple of notes I've already put, but to proceed, I think that I might meed some additional information.
Like requirements. I prepared the list of the questions, answers to them will help me understand what should I check and how.
- What are the targeting versions of esp-idf for examples? (I've tried the
basic_uvc_stream
on v5.2 and there isfatal error: sd_pwr_ctrl_by_on_chip_ldo.h: No such file or directory
😐 - What are the requirements for the driver? Should it notify the user while the device is attached to the ESP32 and then user should start streaming? Or it just provides the possibility to open the stream, when the device is already connected and user knows the vid/pid? More like the general idea. Using with hubs, several streams on one device or not, hot detaching (detaching cameras during streaming) and so on
- Single-thread/Multi-thread. Does it support opening several streams on one physical device from several different tasks?
I have checked the docs/
folder, thanks for the png! (also, if we need to provide special additional information, such as "create" above the arrow, maybe we need to think about renaming the name of the API)
I will proceed with the review, feel free to address current comments.
host/class/uvc/usb_host_uvc_2/include/esp_private/uvc_control.h
Outdated
Show resolved
Hide resolved
enum uvc_host_dev_event { | ||
UVC_HOST_ERROR, /**< USB transfer error */ | ||
UVC_HOST_DEVICE_DISCONNECTED, /**< Device was suddenly disconnected. The stream is stopped. */ | ||
UVC_HOST_FRAME_BUFFER_OVERFLOW, /**< The received frame was discarded because it exceeded the available frame buffer space. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that also an error? Or it is possible to increase the frame_size
right after getting this event?
If this is an error, maybe it could be better:
UVC_HOST_FRAME_BUFFER_OVERFLOW, /**< The received frame was discarded because it exceeded the available frame buffer space. | |
UVC_HOST_ERROR_FRAME_BUFFER_OVERFLOW, /**< The received frame was discarded because it exceeded the available frame buffer space. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The frame buffer size cannot be changed of the UVC stream was opened (I can add this into TODO list)
It's not a real error because the stream continues. It just informs the user that a frame was dropped. If this happens too often, the user can closed the stream and open it again with larger frame buffers...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then maybe?
UVC_HOST_FRAME_BUFFER_OVERFLOW, /**< The received frame was discarded because it exceeded the available frame buffer space. | |
UVC_HOST_DROPPED_FRAMES, /**< The received frame was discarded because it exceeded the available frame buffer space. |
* - ESP_INVALID_ARG: frame or stream_hdl is NULL | ||
* - ESP_FAIL: The frame was not returned to the driver | ||
*/ | ||
esp_err_t uvc_host_frame_return(uvc_host_stream_hdl_t stream_hdl, uvc_host_frame_t *frame); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on the logic, described above, maybe it would be cleaner to name it something like:
esp_err_t uvc_host_frame_return(uvc_host_stream_hdl_t stream_hdl, uvc_host_frame_t *frame); | |
esp_err_t uvc_host_frame_process_complete(uvc_host_stream_hdl_t stream_hdl, uvc_host_frame_t *frame); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, is that possible to avoid returning value in the uvc_host_frame_callback_t
and do that via the uvc_host_frame_process_complete()
call?
If the frame is handled right in the callback, it is possible to call it right from there.
If the frame is not handled in the callback, it will be called someplace else.
WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This naming was taken from esp32-camera
. I'll check if it can be made better
430f7d0
to
f2e7547
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, couple of new comments, but nothing serious.
I will try to verify it on a hardware, should I have some special camera or anything I should know before testing?
Also, did you do any measurements to what extend it is better than the implementation, based on libusb?
UPD: Is our current example in esp-idf is compatible with this new class driver?
|
||
// @todo create a function that will wait for all frames to be returned | ||
if (!uvc_frame_are_all_returned(uvc_stream)) { | ||
vTaskDelay(pdMS_TO_TICKS(70)); // Wait 70ms so the user can return all frames |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems, that this is the right place to add a mutex here....but you already have a TODO here )
xSemaphoreGive((SemaphoreHandle_t)transfer->context); | ||
} | ||
|
||
esp_err_t uvc_host_usb_ctrl(uvc_host_stream_hdl_t stream_hdl, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength, uint8_t *data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we plan to support something else rather then usb?
If no, maybe usb
in not necessary to be in the name.
esp_err_t uvc_host_usb_ctrl(uvc_host_stream_hdl_t stream_hdl, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength, uint8_t *data) | |
esp_err_t uvc_host_ctrl(uvc_host_stream_hdl_t stream_hdl, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength, uint8_t *data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here I wanted to emphasize that it is not 'Camera control' but 'USB Control' request.
I'll go through all function names again and revise it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then "ctrl_request" probably would be a bit better option....
esp_err_t uvc_host_usb_ctrl(uvc_host_stream_hdl_t stream_hdl, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength, uint8_t *data) | |
esp_err_t uvc_host_ctrl_request(uvc_host_stream_hdl_t stream_hdl, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength, uint8_t *data) |
#include "usb/uvc_host.h" | ||
#include "uvc_control.h" | ||
#include "uvc_stream.h" | ||
#include "uvc_types_priv.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need _priv.h
postfix in the filenames?
They are already in the private folder. Or am I missing something?
I mean, I just bumped in that when I tried to find the file, related to "uvc_frame.c" which is usually has the same name, but header. I didn't find it and then I realized that I need to search "_frame_priv.h" )
Just a bit confusing IMHO.
But maybe there is an idea behind such naming.
host/class/uvc/usb_host_uvc_2/examples/basic_uvc_stream/main/basic_uvc_stream.c
Outdated
Show resolved
Hide resolved
host/class/uvc/usb_host_uvc_2/examples/basic_uvc_stream/main/basic_uvc_stream.c
Outdated
Show resolved
Hide resolved
@tore-espressif Will proceed with review shortly... |
@roma-jam that is really weird, Can you share full CFG descriptor? |
USB 2.0 Camera Seems like we have it in host_test, as CANYON_CNE_CWC2. Which probably means that I do smth wrong. UPD: I open the stream on the same device again. But the stream was already opened and interface was claimed, so I don't get any error on that and driver tries to claim the interface one more time. But it is already claimed, that is why the EP already allocated. Good.
|
Yep, I opened the stream, but I keep getting the following error: and I still have no idea why. In process. |
f2e7547
to
104b5c1
Compare
104b5c1
to
a516b6c
Compare
|
||
bool return_frame = true; // Default to returning the frame in case streaming has been stopped | ||
if (invoke_fb_callback) { | ||
memcpy((uvc_host_stream_format_t *)&this_frame->vs_format, &uvc_stream->constant.vs_format, sizeof(uvc_host_stream_format_t)); |
Check warning
Code scanning / clang-tidy
Call to function 'memcpy' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memcpy_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling] Warning
|
||
vs_control->bFormatIndex = format_desc->bFormatIndex; | ||
vs_control->bFrameIndex = frame_desc->bFrameIndex; | ||
vs_control->dwFrameInterval = UVC_DESC_FPS_TO_DWFRAMEINTERVAL(vs_format->fps); // Implicit conversion from float to uint32_t |
Check warning
Code scanning / clang-tidy
The left operand of '!=' is a garbage value [clang-analyzer-core.UndefinedBinaryOperatorResult] Warning
|
||
static inline bool uvc_is_vs_format_equal(const uvc_host_stream_format_t *a, const uvc_host_stream_format_t *b) | ||
{ | ||
if (a->h_res == b->h_res && |
Check warning
Code scanning / clang-tidy
The left operand of '==' is a garbage value [clang-analyzer-core.UndefinedBinaryOperatorResult] Warning
|
||
// Pass the result to user | ||
if (vs_result_ret) { | ||
memcpy(vs_result_ret, &vs_result, sizeof(uvc_vs_ctrl_t)); |
Check warning
Code scanning / clang-tidy
Call to function 'memcpy' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memcpy_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling] Warning
UVC_CHECK(frame && data, ESP_ERR_INVALID_ARG); | ||
UVC_CHECK(frame->data_len + data_len <= frame->data_buffer_len, ESP_ERR_INVALID_SIZE); | ||
|
||
memcpy(frame->data + frame->data_len, data, data_len); |
Check warning
Code scanning / clang-tidy
Call to function 'memcpy' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memcpy_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling] Warning
err, TAG,); | ||
|
||
// Save info | ||
memcpy((uvc_host_stream_format_t *)&uvc_stream->constant.vs_format, &stream_config->vs_format, sizeof(uvc_host_stream_format_t)); |
Check warning
Code scanning / clang-tidy
Call to function 'memcpy' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memcpy_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling] Warning
// For IN transfers we must transfer data ownership to the driver | ||
const bool in_transfer = bmRequestType & USB_BM_REQUEST_TYPE_DIR_IN; | ||
if (!in_transfer) { | ||
memcpy(start_of_data, data, wLength); |
Check warning
Code scanning / clang-tidy
Call to function 'memcpy' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memcpy_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling] Warning
|
||
// For OUT transfers, we must transfer data ownership to user | ||
if (in_transfer) { | ||
memcpy(data, start_of_data, wLength); |
Check warning
Code scanning / clang-tidy
Call to function 'memcpy' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memcpy_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling] Warning
UVC_EXIT_CRITICAL(); | ||
|
||
if (invoke_fb_callback) { | ||
memcpy((uvc_host_stream_format_t *)&this_frame->vs_format, &uvc_stream->constant.vs_format, sizeof(uvc_host_stream_format_t)); |
Check warning
Code scanning / clang-tidy
Call to function 'memcpy' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memcpy_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling] Warning
This driver does not use libuvc anymore, it is native to Espressif's USB Host Library
a516b6c
to
df83b49
Compare
The last commit adds the following:
Overall, this is Release candidate for v2. Other features and bugs will be addressed in bugfix releases |
Introduction
This PR introduces version 2 of the USB Host UVC driver, aimed at enabling ESP SoCs to stream frames from connected USB cameras.
The driver provides frames to the user via a callback, offering a flexible interface that can serve as a foundation for more advanced frame processing applications.
Internally, the driver manages a FreeRTOS Queue containing multiple frame buffers, which helps prevent buffer overflows and underflows during streaming.
Detailed feature descriptions, future plans, and usage instructions are available in the README.md file.
Information for Testers
This section provides instructions for testing the driver’s functionality and public API.
Two examples are included for testing:
1.
basic_uvc_stream
2.
camera_display
Information for Reviewers
This section provides guidance for those reviewing the internal code structure of the driver.
The driver includes a
host_test
folder with tests designed to run on Linux. These tests use a mocked version of the esp-idf/usb component, focusing on the following areas, which should need less in-depth review:uvc_descriptor_parsing.c
uvc_isoc.c
anduvc_bulk.c
The following file, focused on human-readable output, also requires only a light review:
uvc_descriptor_printing.c
Areas not yet covered by
host_tests
and requiring more detailed review include:uvc_frame.c
(manages queue of empty frame buffers)uvc_control.c
(handles video format negotiation and other control requests)uvc_host.c
(includes driver installation, device management, stream initiation, etc.)Related Information